#include <string.h>

#include "esp_log.h"
#include "esp_smartconfig.h"
#include "esp_wifi.h"

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"

#include "my_wifi.h"
#include "my_nvs.h"
#include "my_common.h"
#include "my_mqtt.h"

static const char *TAG = "WIFI";

// 事件组
static EventGroupHandle_t my_event_group;
// ESP TOUCH 配网完成标志
static const int BIT_ESPTOUCH_DONE = BIT0;

/**
 * @brief SmartConfig事件的回调函数，用于配置网络，并将配置信息保存到nvs中
 */
static void smartconfig_task(void *parm)
{
    EventBits_t uxBits;
    ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_V2));
    smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_smartconfig_start(&cfg));
    while (1)
    {
        uxBits = xEventGroupWaitBits(my_event_group, BIT_ESPTOUCH_DONE, true, false, portMAX_DELAY);
        if (uxBits & BIT_ESPTOUCH_DONE)
        {
            esp_smartconfig_stop();
            vTaskDelete(NULL);
        }
    }
}

static void event_handler(void *event_handler_arg,
                          esp_event_base_t event_base,
                          int32_t event_id,
                          void *event_data)
{
    // WiFi事件，已经准备好连接
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        if (is_wifi_configured())
        {
            ESP_ERROR_CHECK(esp_wifi_connect());
        }
        else
        {
            xTaskCreate(smartconfig_task, "smartconfig_task", 4096, NULL, 3, NULL);
        }
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        ESP_LOGI(TAG, "WiFi断开连接");
        ESP_ERROR_CHECK(esp_wifi_connect());
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));

        set_wifi_configured();

        mqtt_app_start();
    }
    // SmartConfig事件，获得WiFi SSID和密码，保存到nvs中
    else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD)
    {
        smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
        ESP_LOGI(TAG, "SSID: %s", evt->ssid);
        ESP_LOGI(TAG, "password: %s", evt->password);

        wifi_config_t wifi_config;
        bzero(&wifi_config, sizeof(wifi_config_t));
        memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
        memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.ssid));

        // 获取mqtt broker地址
        char my_mqtt_uri[MQTT_URI_LEN];
        ESP_ERROR_CHECK(esp_smartconfig_get_rvd_data((uint8_t *)my_mqtt_uri, sizeof(my_mqtt_uri)));

        ESP_LOGI(TAG, "MQTT: %s", my_mqtt_uri);
        persist_mqtt_uri(my_mqtt_uri);

        ESP_ERROR_CHECK(esp_wifi_disconnect());
        ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
        ESP_LOGI(TAG, "connecting to %s", wifi_config.sta.ssid);
        ESP_ERROR_CHECK(esp_wifi_connect());
    }
    else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE)
    {
        xEventGroupSetBits(my_event_group, BIT_ESPTOUCH_DONE);
    }
}
void start_wifi(void)
{
    my_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);
    wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));

    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT,
                                               ESP_EVENT_ANY_ID,
                                               &event_handler,
                                               NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT,
                                               ESP_EVENT_ANY_ID,
                                               &event_handler,
                                               NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(SC_EVENT,
                                               ESP_EVENT_ANY_ID,
                                               &event_handler,
                                               NULL));

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    wifi_config_t wifi_config;
    ESP_ERROR_CHECK(esp_wifi_get_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
}